package net.socket.server;


import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import manager.connection.ClientConnectionManager;
import net.socket.server.message.MessageManager;
import net.socket.server.message.base.IMessageBody;
import net.socket.server.message.base.MessageHeader;
import net.socket.server.notification.MachineIDLeavedNTF;
import net.socket.server.protocal.PROTOID;
import net.socket.server.request.IRequest;
import net.socket.server.request.MachineLoginRequest;
import observable.subject.MessageCenter;
import util.MyFactory;
import util.ResultTypeList;



import org.apache.log4j.Logger;

import com.fasterxml.jackson.core.JsonProcessingException;

import advice.ExceptionManager;
import io.netty.buffer.ByteBuf;

public class SocketServerInboundHandler extends ChannelInboundHandlerAdapter{
	
	private static Logger logger = Logger.getLogger(ExceptionManager.class);
	private int machineID = -1;
	private boolean connectChecked = false; 
	private MessageManager messageManager = MyFactory.context.getBean("MessageManager", MessageManager.class);
	@Override 
	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause){
		//System.out.println("exceptionCaught machineID: " + cause.toString());
		//ClientConnectionManager ccm = new ClientConnectionManager();
		System.out.println("exceptionCaught machineID: " + this.machineID);
		logger.info("exceptionCaught machineID:"+this.machineID);
		//ccm.removeConnection(this.machineID);
	    ctx.close();
	}
	
	
	
	@Override
	public void channelInactive(ChannelHandlerContext ctx) throws Exception {
		super.channelInactive(ctx);
		//ClientConnectionManager ccm = new ClientConnectionManager();
		//ccm.removeConnection(this.machineID);
		//System.out.println("channelInactive:"+this.machineID);
		logger.info("channelInactive:"+this.machineID);
		//ctx.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE);
		ctx.close();
	}

	@Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { 
		ByteBuf buf = null;
		try{
			buf = (ByteBuf)msg;
			
			//System.out.println("buf ref count: " + buf.refCnt());
			//System.out.println("get connection: " + ctx.channel().remoteAddress());
			MessageHeader header = MyFactory.context.getBean("MessageHeader", MessageHeader.class);
			header.decode(buf);
			MessageCenter mc = MyFactory.context.getBean("MessageCenter", MessageCenter.class);
//			if(header.getCommand()!=PROTOID.REQ_TRANSPOND_SOCRE)
//				logger.info("get command: " + header.getCommand() + " from matchine: " + header.getMachineID());
			System.out.println("get command: " + header.getCommand() + " from matchine: " + header.getMachineID());	
			IMessageBody body = messageManager.chooseMessageBody(header);
			body.decode(buf);			
			IRequest request = messageManager.translateToRequest(header, body);
			/*
			 * 如果comd是机器登陆请求就执行机器登陆，如果机器已经登陆，则执行cmd请求
			 */
			if(request == null){
				//System.out.println("translate fail");
				logger.info("translate fail");
			}else if(header.getCommand() == PROTOID.LOGIN_GAME_SVR_REQ){
				System.out.println("getCommd login_game_svr_req_______________");
				this.machineID = header.getMachineID();
				
				connectChecked = true;//机器连接状态设置为true
				((MachineLoginRequest)request).setCtx(ctx);
				mc.distribute(PROTOID.LOGIN_GAME_SVR_REQ, request);//登陆消息转发，由MessageCenter
			}
			else if(connectChecked == true && machineID == header.getMachineID()){
				mc.distribute(header.getCommand(), request);//cmd消息转发处理，由MessageCenter
			}
			else{
				throw new Exception("unrecognized request: " + header.getCommand() + ", or no login performed");
			}
		}
		finally{
			if(buf != null){
				System.out.println("buf ref count after execution: " + buf.refCnt());
				buf.release();
			}	
		}
	}

	public void kickMachine(int mid) throws IllegalArgumentException, IllegalAccessException, JsonProcessingException {
		System.out.println("kickMachine:");
		ClientConnectionManager ccm = new ClientConnectionManager();
		if(null!=ccm.getConnectionInfo(mid)&&mid==ccm.getConnectionInfo(mid).getMachineId()) {
			MachineIDLeavedNTF rsp = new MachineIDLeavedNTF();
			rsp.setErrorCode(ResultTypeList.GM_LET_MACHINE_LEAVE);
			ccm.sendResponse(PROTOID.NTF_MACHINELEAVED, mid, rsp);
			ccm.getConnectionInfo(mid).getCtx().close();
			ccm.removeConnection(mid);
			System.out.println("kickMachine :"+mid);
			logger.info("kickMachine :"+mid);
		}			
		}	
	
	}
